home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / MultiAnimation / MultiAnimation.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-28  |  38.2 KB  |  903 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: MultiAnimation.cpp
  3. //
  4. // Starting point for new Direct3D applications
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #include "resource.h"
  10. #include "DXUTsound.h"
  11. #include "MultiAnimation.h"
  12. #include "Tiny.h"
  13.  
  14.  
  15. using namespace std;
  16.  
  17.  
  18. #define TXFILE_FLOOR L"floor.jpg"
  19. #define FLOOR_TILECOUNT 2
  20.  
  21.  
  22. //--------------------------------------------------------------------------------------
  23. // Global variables
  24. //--------------------------------------------------------------------------------------
  25. ID3DXFont*              g_pFont = NULL;         // Font for drawing text
  26. ID3DXSprite*            g_pTextSprite = NULL;   // Sprite for batching draw text calls
  27. ID3DXEffect*            g_pEffect = NULL;       // D3DX effect interface
  28. CFirstPersonCamera      g_Camera;               // A model viewing camera
  29. CDXUTDialog             g_HUD;                  // dialog for standard controls
  30. CDXUTDialog             g_SampleUI;             // dialog for sample specific controls
  31. ID3DXMesh*              g_pMeshFloor = NULL;    // floor geometry
  32. D3DXMATRIXA16           g_mxFloor;              // floor world xform
  33. D3DMATERIAL9            g_MatFloor;             // floor material
  34. IDirect3DTexture9*      g_pTxFloor = NULL;      // floor texture
  35. CSoundManager           g_DSound;               // DSound class
  36. CMultiAnim              g_MultiAnim;            // the MultiAnim class for holding Tiny's mesh and frame hierarchy
  37. vector< CTiny* >        g_v_pCharacters;        // array of character objects; each can be associated with any of the CMultiAnims
  38. DWORD                   g_dwFollow = 0xffffffff;// which character the camera should follow; 0xffffffff for static camera
  39. bool                    g_bShowHelp = true;     // If true, it renders the UI control text
  40. bool                    g_bPlaySounds = true;   // whether to play sounds
  41. double                  g_fLastAnimTime = 0.0;  // Time for the animations
  42.  
  43.  
  44. //--------------------------------------------------------------------------------------
  45. // UI control IDs
  46. //--------------------------------------------------------------------------------------
  47. #define IDC_TOGGLEFULLSCREEN    1
  48. #define IDC_TOGGLEREF           3
  49. #define IDC_CHANGEDEVICE        4
  50. #define IDC_ADDTINY             5
  51. #define IDC_NEXTVIEW            6
  52. #define IDC_PREVVIEW            7
  53. #define IDC_ENABLESOUND         8
  54. #define IDC_CONTROLTINY         9
  55. #define IDC_RELEASEALL          10
  56. #define IDC_RESETCAMERA         11
  57. #define IDC_RESETTIME           12
  58.  
  59.  
  60. //--------------------------------------------------------------------------------------
  61. // Forward declarations 
  62. //--------------------------------------------------------------------------------------
  63. bool    CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed );
  64. void    CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps );
  65. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  66. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  67. void    CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  68. void    CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  69. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing );
  70. void    CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown  );
  71. void    CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl );
  72. void    CALLBACK OnLostDevice();
  73. void    CALLBACK OnDestroyDevice();
  74.  
  75. void    InitApp();
  76. HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh );
  77. void    RenderText();
  78.  
  79.  
  80. //--------------------------------------------------------------------------------------
  81. // Entry point to the program. Initializes everything and goes into a message processing 
  82. // loop. Idle time is used to render the scene.
  83. //--------------------------------------------------------------------------------------
  84. INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  85. {
  86.     // Set the callback functions. These functions allow the sample framework to notify
  87.     // the application about device changes, user input, and windows messages.  The 
  88.     // callbacks are optional so you need only set callbacks for events you're interested 
  89.     // in. However, if you don't handle the device reset/lost callbacks then the sample 
  90.     // framework won't be able to reset your device since the application must first 
  91.     // release all device resources before resetting.  Likewise, if you don't handle the 
  92.     // device created/destroyed callbacks then the sample framework won't be able to 
  93.     // recreate your device resources.
  94.     DXUTSetCallbackDeviceCreated( OnCreateDevice );
  95.     DXUTSetCallbackDeviceReset( OnResetDevice );
  96.     DXUTSetCallbackDeviceLost( OnLostDevice );
  97.     DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
  98.     DXUTSetCallbackMsgProc( MsgProc );
  99.     DXUTSetCallbackKeyboard( KeyboardProc );
  100.     DXUTSetCallbackFrameRender( OnFrameRender );
  101.     DXUTSetCallbackFrameMove( OnFrameMove );
  102.  
  103.     // Show the cursor and clip it when in full screen
  104.     DXUTSetCursorSettings( true, true );
  105.  
  106.     InitApp();
  107.  
  108.     // Initialize the sample framework and create the desired Win32 window and Direct3D 
  109.     // device for the application. Calling each of these functions is optional, but they
  110.     // allow you to set several options which control the behavior of the framework.
  111.     DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  112.     DXUTCreateWindow( L"MultiAnimation" );
  113.  
  114.     // We need to set up dsound after we have a window.
  115.     g_DSound.Initialize( DXUTGetHWND(), DSSCL_PRIORITY );
  116.  
  117.     DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
  118.  
  119.     // Pass control to the sample framework for handling the message pump and 
  120.     // dispatching render calls. The sample framework will call your FrameMove 
  121.     // and FrameRender callback when there is idle time between handling window messages.
  122.     DXUTMainLoop();
  123.  
  124.     // Perform any application-level cleanup here. Direct3D device resources are released within the
  125.     // appropriate callback functions and therefore don't require any cleanup code here.
  126.     vector< CTiny* >::iterator itCurCP, itEndCP = g_v_pCharacters.end();
  127.     for( itCurCP = g_v_pCharacters.begin(); itCurCP != itEndCP; ++ itCurCP )
  128.     {
  129.         ( * itCurCP )->Cleanup();
  130.         delete * itCurCP;
  131.     }
  132.     g_v_pCharacters.clear();
  133.  
  134.     delete g_apSoundsTiny[ 0 ];
  135.     delete g_apSoundsTiny[ 1 ];
  136.  
  137.     return DXUTGetExitCode();
  138. }
  139.  
  140.  
  141. //--------------------------------------------------------------------------------------
  142. // Initialize the app 
  143. //--------------------------------------------------------------------------------------
  144. void InitApp()
  145. {
  146.     // Initialize dialogs
  147.     g_HUD.SetCallback( OnGUIEvent ); int iY = 10;
  148.     g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
  149.     g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
  150.     g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22 );
  151.  
  152.     g_SampleUI.SetCallback( OnGUIEvent ); iY = 10;
  153.     g_SampleUI.AddButton( IDC_ADDTINY, L"Add Instance", 45, iY, 120, 24 );
  154.     g_SampleUI.AddButton( IDC_NEXTVIEW, L"(N)ext View", 45, iY += 26, 120, 24, L'N' );
  155.     g_SampleUI.AddButton( IDC_PREVVIEW, L"(P)revious View", 45, iY += 26, 120, 24, L'P' );
  156.     g_SampleUI.AddButton( IDC_RESETCAMERA, L"(R)eset view", 45, iY += 26, 120, 24, L'R' );
  157.     g_SampleUI.AddCheckBox( IDC_ENABLESOUND, L"Enable sound", 25, iY += 26, 140, 24, true );
  158.     g_SampleUI.AddCheckBox( IDC_CONTROLTINY, L"(C)ontrol this instance", 25, iY += 26, 140, 24, false, L'C' );
  159.     g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetVisible( false );
  160.     g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetEnabled( false );
  161.     g_SampleUI.AddButton( IDC_RELEASEALL, L"Auto-control all", 45, iY += 26, 120, 24 );
  162.     g_SampleUI.AddButton( IDC_RESETTIME, L"Reset time", 45, iY += 26, 120, 24 );
  163.  
  164.     // Setup the camera with view matrix
  165.     D3DXVECTOR3 vEye( .5f, .55f, -.2f );
  166.     D3DXVECTOR3 vAt( .5f,  .125f, .5f );
  167.     g_Camera.SetViewParams( &vEye, &vAt );
  168.     g_Camera.SetScalers( 0.01f, 1.0f );  // Camera movement parameters
  169. }
  170.  
  171.  
  172. //--------------------------------------------------------------------------------------
  173. // Called during device initialization, this code checks the device for some 
  174. // minimum set of capabilities, and rejects those that don't pass by returning false.
  175. //--------------------------------------------------------------------------------------
  176. bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 
  177.                                   D3DFORMAT BackBufferFormat, bool bWindowed )
  178. {
  179.     // Skip backbuffer formats that don't support alpha blending
  180.     IDirect3D9* pD3D = DXUTGetD3DObject();
  181.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  182.                     AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
  183.                     D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
  184.         return false;
  185.  
  186.     // Need to support ps 1.1
  187.     if( pCaps->PixelShaderVersion < D3DPS_VERSION( 1, 1 ) )
  188.         return false;
  189.  
  190.     // Need to support A8R8G8B8 textures
  191.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  192.                                          AdapterFormat, 0,
  193.                                          D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8 ) ) )
  194.         return false;
  195.  
  196.     return true;
  197. }
  198.  
  199.  
  200. //--------------------------------------------------------------------------------------
  201. // This callback function is called immediately before a device is created to allow the 
  202. // application to modify the device settings. The supplied pDeviceSettings parameter 
  203. // contains the settings that the framework has selected for the new device, and the 
  204. // application can make any desired changes directly to this structure.  Note however that 
  205. // the sample framework will not correct invalid device settings so care must be taken 
  206. // to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.
  207. //--------------------------------------------------------------------------------------
  208. void CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps )
  209. {
  210.     // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  211.     // then switch to SWVP.
  212.     if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
  213.          pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
  214.     {
  215.         pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  216.     }
  217.     else
  218.     {
  219.         pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  220.     }
  221.  
  222.     // This application is designed to work on a pure device by not using 
  223.     // IDirect3D9::Get*() methods, so create a pure device if supported and using HWVP.
  224.     if ((pCaps->DevCaps & D3DDEVCAPS_PUREDEVICE) != 0 && 
  225.         (pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 )
  226.         pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;
  227.  
  228.      // If the hardware cannot do vertex blending, use software vertex processing.
  229.     if( pCaps->MaxVertexBlendMatrices < 2 )
  230.         pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  231.  
  232.     // If using hardware vertex processing, change to mixed vertex processing
  233.     // so there is a fallback.
  234.     if( pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
  235.         pDeviceSettings->BehaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;    
  236.  
  237.     // Debugging vertex shaders requires either REF or software vertex processing 
  238.     // and debugging pixel shaders requires REF.  
  239. #ifdef DEBUG_VS
  240.     if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
  241.     {
  242.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  243.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;
  244.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  245.     }
  246. #endif
  247. #ifdef DEBUG_PS
  248.     pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  249. #endif
  250. }
  251.  
  252.  
  253. //--------------------------------------------------------------------------------------
  254. // This callback function will be called immediately after the Direct3D device has been 
  255. // created, which will happen during application initialization and windowed/full screen 
  256. // toggles. This is the best location to create D3DPOOL_MANAGED resources since these 
  257. // resources need to be reloaded whenever the device is destroyed. Resources created  
  258. // here should be released in the OnDestroyDevice callback. 
  259. //--------------------------------------------------------------------------------------
  260. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  261. {
  262.     HRESULT hr;
  263.  
  264.     // Initialize the font
  265.     V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, 
  266.                          OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  267.                          L"Arial", &g_pFont ) );
  268.  
  269.     // Initialize floor textures
  270.     WCHAR str[MAX_PATH];
  271.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, TXFILE_FLOOR ) );
  272.     V_RETURN( D3DXCreateTextureFromFile( pd3dDevice, str, &g_pTxFloor ) );
  273.  
  274.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  275.     // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  276.     // processing, and debugging pixel shaders requires REF.  The 
  277.     // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the 
  278.     // shader debugger.  It enables source level debugging, prevents instruction 
  279.     // reordering, prevents dead code elimination, and forces the compiler to compile 
  280.     // against the next higher available software target, which ensures that the 
  281.     // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  282.     // flags will cause slower rendering since the shaders will be unoptimized and 
  283.     // forced into software.  See the DirectX documentation for more information about 
  284.     // using the shader debugger.
  285.     DWORD dwShaderFlags = 0;
  286.     #ifdef DEBUG_VS
  287.         dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  288.     #endif
  289.     #ifdef DEBUG_PS
  290.         dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  291.     #endif
  292.  
  293.     // Read the D3DX effect file
  294.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"MultiAnimation.fx" ) );
  295.  
  296.     // If this fails, there should be debug output as to 
  297.     // they the .fx file failed to compile
  298.     V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, 
  299.                                         NULL, &g_pEffect, NULL ) );
  300.     g_pEffect->SetTechnique( "RenderScene" );
  301.  
  302.     D3DXMATRIX mx;
  303.     // floor geometry transform
  304.     D3DXMatrixRotationX( & g_mxFloor, -D3DX_PI / 2.0f );
  305.     D3DXMatrixRotationY( & mx, D3DX_PI / 4.0f );
  306.     D3DXMatrixMultiply( & g_mxFloor, & g_mxFloor, & mx );
  307.     D3DXMatrixTranslation( & mx, 0.5f, 0.0f, 0.5f );
  308.     D3DXMatrixMultiply( & g_mxFloor, & g_mxFloor, & mx );
  309.  
  310.     // set material for floor
  311.     g_MatFloor.Diffuse = D3DXCOLOR( 1.f, 1.f, 1.f, .75f );
  312.     g_MatFloor.Ambient = D3DXCOLOR( 1.f, 1.f, 1.f, 1.f );
  313.     g_MatFloor.Specular = D3DXCOLOR( 0.f, 0.f, 0.f, 1.f );
  314.     g_MatFloor.Emissive = D3DXCOLOR( .0f, 0.f, 0.f, 0.f );
  315.     g_MatFloor.Power = 0.f;
  316.  
  317.     return S_OK;
  318. }
  319.  
  320.  
  321. //--------------------------------------------------------------------------------------
  322. // This callback function will be called immediately after the Direct3D device has been 
  323. // reset, which will happen after a lost device scenario. This is the best location to 
  324. // create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever 
  325. // the device is lost. Resources created here should be released in the OnLostDevice 
  326. // callback. 
  327. //--------------------------------------------------------------------------------------
  328. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
  329.                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  330. {
  331.     HRESULT hr;
  332.  
  333.     // set up MultiAnim
  334.     WCHAR sXFile[MAX_PATH];
  335.     WCHAR str[MAX_PATH];
  336.  
  337.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"MultiAnimation.fx" ) );
  338.     V_RETURN( DXUTFindDXSDKMediaFileCch( sXFile, MAX_PATH, L"tiny_4anim.x" ) );
  339.  
  340.     CMultiAnimAllocateHierarchy AH;
  341.     AH.SetMA( & g_MultiAnim );
  342.  
  343.     V_RETURN( g_MultiAnim.Setup( pd3dDevice, sXFile, str, &AH ) );
  344.  
  345.     // get device caps
  346.     D3DCAPS9 caps;
  347.     pd3dDevice->GetDeviceCaps( & caps );
  348.  
  349.     // Select the technique that fits the shader version.
  350.     // We could have used ValidateTechnique()/GetNextValidTechnique() to find the
  351.     // best one, but this is convenient for our purposes.
  352.     if( caps.VertexShaderVersion >= D3DVS_VERSION( 2, 0 ) )
  353.         g_MultiAnim.SetTechnique( "Skinning20" );
  354.     else
  355.         g_MultiAnim.SetTechnique( "Skinning11" );
  356.  
  357.     // Restore steps for tiny instances
  358.     vector< CTiny* >::iterator itCurCP, itEndCP = g_v_pCharacters.end();
  359.     for( itCurCP = g_v_pCharacters.begin(); itCurCP != itEndCP; ++ itCurCP )
  360.     {
  361.         ( * itCurCP )->RestoreDeviceObjects( pd3dDevice );
  362.     }
  363.  
  364.     // If there is no instance, make sure we have at least one.
  365.     if( g_v_pCharacters.size() == 0 )
  366.     {
  367.         CTiny * pTiny = new CTiny;
  368.         if( pTiny == NULL )
  369.             return E_OUTOFMEMORY;
  370.  
  371.         hr = pTiny->Setup( & g_MultiAnim, & g_v_pCharacters, & g_DSound, 0.f );
  372.         pTiny->SetSounds( g_bPlaySounds );
  373.     }
  374.  
  375.     if( g_pFont )
  376.         V_RETURN( g_pFont->OnResetDevice() );
  377.     if( g_pEffect )
  378.         V_RETURN( g_pEffect->OnResetDevice() );
  379.     ID3DXEffect *pMAEffect = g_MultiAnim.GetEffect();
  380.     if( pMAEffect )
  381.     {
  382.         pMAEffect->OnResetDevice();
  383.         pMAEffect->Release();
  384.     }
  385.  
  386.     // Create a sprite to help batch calls when drawing many lines of text
  387.     V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );
  388.  
  389.     // Setup the camera's projection parameters
  390.     float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
  391.     g_Camera.SetProjParams( D3DX_PI/3, fAspectRatio, 0.001f, 100.0f );
  392.  
  393.     // set lighting
  394.     pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  395.     pd3dDevice->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_ARGB( 255, 255, 255, 255 ) );
  396.     pd3dDevice->LightEnable( 0, TRUE );
  397.     pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE );
  398.  
  399.     // create the floor geometry
  400.     LPD3DXMESH pMesh;
  401.     V_RETURN( D3DXCreatePolygon( pd3dDevice, 1.2f, 4, & pMesh, NULL ) );
  402.     V_RETURN( pMesh->CloneMeshFVF( D3DXMESH_WRITEONLY, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1, pd3dDevice, & g_pMeshFloor ) );
  403.     SAFE_RELEASE( pMesh );
  404.  
  405.     DWORD dwNumVx = g_pMeshFloor->GetNumVertices();
  406.  
  407.     struct Vx
  408.     {
  409.         D3DXVECTOR3 vPos;
  410.         D3DXVECTOR3 vNorm;
  411.         float fTex[ 2 ];
  412.     };
  413.  
  414.     // Initialize its texture coordinates
  415.     Vx * pVx;
  416.     hr = g_pMeshFloor->LockVertexBuffer( 0, (VOID **) & pVx );
  417.     if( FAILED( hr ) )
  418.         return hr;
  419.  
  420.     for( DWORD i = 0; i < dwNumVx; ++ i )
  421.     {
  422.         if( fabs( pVx->vPos.x ) < 0.01 )
  423.         {
  424.             if( pVx->vPos.y > 0 )
  425.             {
  426.                 pVx->fTex[ 0 ] = 0.0f;
  427.                 pVx->fTex[ 1 ] = 0.0f;
  428.             } else
  429.             if( pVx->vPos.y < 0.0f )
  430.             {
  431.                 pVx->fTex[ 0 ] = 1.0f * FLOOR_TILECOUNT;
  432.                 pVx->fTex[ 1 ] = 1.0f * FLOOR_TILECOUNT;
  433.             } else
  434.             {
  435.                 pVx->fTex[ 0 ] = 0.5f * FLOOR_TILECOUNT;
  436.                 pVx->fTex[ 1 ] = 0.5f * FLOOR_TILECOUNT;
  437.             }
  438.         } else
  439.         if( pVx->vPos.x > 0.0f )
  440.         {
  441.             pVx->fTex[ 0 ] = 1.0f * FLOOR_TILECOUNT;
  442.             pVx->fTex[ 1 ] = 0.0f;
  443.         } else
  444.         {
  445.             pVx->fTex[ 0 ] = 0.0f;
  446.             pVx->fTex[ 1 ] = 1.0f * FLOOR_TILECOUNT;
  447.         }
  448.  
  449.         ++ pVx;
  450.     }
  451.  
  452.     g_pMeshFloor->UnlockVertexBuffer();
  453.  
  454.     // reset the timer
  455.     g_fLastAnimTime = DXUTGetGlobalTimer()->GetTime();;
  456.  
  457.     // Adjust the dialog parameters.
  458.     g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
  459.     g_HUD.SetSize( 170, 170 );
  460.     g_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width-170, pBackBufferSurfaceDesc->Height-270 );
  461.     g_SampleUI.SetSize( 170, 220 );
  462.  
  463.     return S_OK;
  464. }
  465.  
  466.  
  467. //--------------------------------------------------------------------------------------
  468. // This callback function will be called once at the beginning of every frame. This is the
  469. // best location for your application to handle updates to the scene, but is not 
  470. // intended to contain actual rendering calls, which should instead be placed in the 
  471. // OnFrameRender callback.  
  472. //--------------------------------------------------------------------------------------
  473. void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  474. {
  475.     vector< CTiny* >::iterator itCur, itEnd = g_v_pCharacters.end();
  476.     for( itCur = g_v_pCharacters.begin(); itCur != itEnd; ++ itCur )
  477.         ( * itCur )->Animate( fTime - g_fLastAnimTime );
  478.  
  479.     g_fLastAnimTime = fTime;
  480.  
  481.     // Update the camera's position based on user input 
  482.     g_Camera.FrameMove( fElapsedTime );
  483. }
  484.  
  485.  
  486. //--------------------------------------------------------------------------------------
  487. // This callback function will be called at the end of every frame to perform all the 
  488. // rendering calls for the scene, and it will also be called if the window needs to be 
  489. // repainted. After this function has returned, the sample framework will call 
  490. // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
  491. //--------------------------------------------------------------------------------------
  492. void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  493. {
  494.     HRESULT hr;
  495.  
  496.     pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 
  497.                        D3DCOLOR_ARGB( 0, 0x3F, 0xAF, 0xFF ), 1.0f, 0L );
  498.  
  499.     if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  500.     {
  501.         // set up the camera
  502.         D3DXMATRIXA16 mx, mxView, mxProj;
  503.         D3DXVECTOR3 vEye;
  504.         D3DXVECTOR3 vLightDir;
  505.  
  506.         // are we following a tiny, or an independent arcball camera?
  507.         if( g_dwFollow == 0xffffffff )
  508.         {
  509.             // Light direction is same as camera front (reversed)
  510.             vLightDir = -(*g_Camera.GetWorldAhead());
  511.             
  512.             // set static transforms
  513.             mxView = *g_Camera.GetViewMatrix();
  514.             mxProj = *g_Camera.GetProjMatrix();
  515.             V( pd3dDevice->SetTransform( D3DTS_VIEW, & mxView ) );
  516.             V( pd3dDevice->SetTransform( D3DTS_PROJECTION, & mxProj ) );
  517.             vEye = *g_Camera.GetEyePt();
  518.         }
  519.         else
  520.         {
  521.             // set follow transforms
  522.             CTiny * pChar = g_v_pCharacters[ g_dwFollow ];
  523.  
  524.             D3DXVECTOR3 vCharPos;
  525.             D3DXVECTOR3 vCharFacing;
  526.             pChar->GetPosition( & vCharPos );
  527.             pChar->GetFacing( & vCharFacing );
  528.             vEye = D3DXVECTOR3  ( vCharPos.x, 0.25f, vCharPos.z );
  529.             D3DXVECTOR3 vAt     ( vCharPos.x, 0.0125f, vCharPos.z ),
  530.                         vUp     ( 0.0f, 1.0f, 0.0f );
  531.             vCharFacing.x *= .25; vCharFacing.y = 0.f; vCharFacing.z *= .25;
  532.             vEye -= vCharFacing;
  533.             vAt += vCharFacing;
  534.  
  535.             D3DXMatrixLookAtLH( & mxView, & vEye, & vAt, & vUp );
  536.             V( pd3dDevice->SetTransform( D3DTS_VIEW, & mxView ) );
  537.  
  538.             const D3DSURFACE_DESC *pBackBufferSurfaceDesc = DXUTGetBackBufferSurfaceDesc();
  539.             float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
  540.             D3DXMatrixPerspectiveFovLH( &mxProj, D3DX_PI / 3, fAspectRatio, 0.1f, 100.0f );
  541.             V( pd3dDevice->SetTransform( D3DTS_PROJECTION, & mxProj ) );
  542.  
  543.             // Set the light direction and normalize
  544.             D3DXVec3Subtract( &vLightDir, &vEye, &vAt );
  545.             D3DXVec3Normalize( &vLightDir, &vLightDir );
  546.         }
  547.  
  548.         // set view-proj
  549.         D3DXMatrixMultiply( & mx, & mxView, & mxProj );
  550.         g_pEffect->SetMatrix( "g_mViewProj", & mx );
  551.         ID3DXEffect *pMAEffect = g_MultiAnim.GetEffect();
  552.         if( pMAEffect )
  553.         {
  554.             pMAEffect->SetMatrix( "g_mViewProj", & mx );
  555.         }
  556.  
  557.         // Set the light direction so that the
  558.         // visible side is lit.
  559.         D3DXVECTOR4 v( vLightDir.x, vLightDir.y, vLightDir.z, 1.0f );
  560.         g_pEffect->SetVector( "lhtDir", &v );
  561.         if( pMAEffect )
  562.             pMAEffect->SetVector( "lhtDir", &v );
  563.  
  564.         SAFE_RELEASE( pMAEffect );
  565.  
  566.         // set the fixed function shader for drawing the floor
  567.         V( pd3dDevice->SetFVF( g_pMeshFloor->GetFVF() ) );
  568.  
  569.         // Draw the floor
  570.         V( g_pEffect->SetTexture( "g_txScene", g_pTxFloor ) );
  571.         V( g_pEffect->SetMatrix( "g_mWorld", &g_mxFloor ) );
  572.         UINT cPasses;
  573.         V( g_pEffect->Begin( &cPasses, 0 ) );
  574.         for( UINT p = 0; p < cPasses; ++p )
  575.         {
  576.             V( g_pEffect->BeginPass( p ) );
  577.             V( g_pMeshFloor->DrawSubset( 0 ) );
  578.             V( g_pEffect->EndPass() );
  579.         }
  580.         V( g_pEffect->End() );
  581.  
  582.         // draw each tiny
  583.         vector< CTiny* >::iterator itCur, itEnd = g_v_pCharacters.end();
  584.         for( itCur = g_v_pCharacters.begin(); itCur != itEnd; ++ itCur )
  585.         {
  586.             // set the time to update the hierarchy
  587.             ( * itCur )->AdvanceTime( fElapsedTime, & vEye );
  588.             // draw the mesh
  589.             ( * itCur )->Draw();
  590.         }
  591.  
  592.         //
  593.         // Output text information
  594.         //
  595.         RenderText();
  596.  
  597.         V( g_HUD.OnRender( fElapsedTime ) );
  598.         V( g_SampleUI.OnRender( fElapsedTime ) );
  599.  
  600.         pd3dDevice->EndScene();
  601.     }
  602. }
  603.  
  604.  
  605. //--------------------------------------------------------------------------------------
  606. // Render the help and statistics text. This function uses the ID3DXFont interface for 
  607. // efficient text rendering.
  608. //--------------------------------------------------------------------------------------
  609. void RenderText()
  610. {
  611.     // The helper object simply helps keep track of text position, and color
  612.     // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
  613.     // If NULL is passed in as the sprite object, then it will work however the 
  614.     // pFont->DrawText() will not be batched together.  Batching calls will improves performance.
  615.     CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
  616.     const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  617.  
  618.     // Output statistics
  619.     txtHelper.Begin();
  620.     txtHelper.SetInsertionPos( 5, 5 );
  621.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  622.     txtHelper.DrawTextLine( DXUTGetFrameStats() );
  623.     txtHelper.DrawTextLine( DXUTGetDeviceStats() );
  624.     
  625.     // Dump out the FPS and device stats
  626.     txtHelper.SetInsertionPos( 5, 37 );
  627.     txtHelper.DrawFormattedTextLine( L"  Time: %2.3f", DXUTGetGlobalTimer()->GetTime() );
  628.     txtHelper.DrawFormattedTextLine( L"  Number of models: %d", g_v_pCharacters.size() );
  629.  
  630.     txtHelper.SetInsertionPos( 5, 70 );
  631.  
  632.     // We can only display either the behavior text or help text,
  633.     // with the help text having priority.
  634.     if( g_bShowHelp )
  635.     {
  636.         // output data for T[m_dwFollow]
  637.         if( g_dwFollow != -1 )
  638.         {
  639.             txtHelper.DrawTextLine( L"Press F1 to hide animation info\n"
  640.                                     L"Quit: Esc" );
  641.  
  642.             if( g_v_pCharacters[ g_dwFollow]->IsUserControl() )
  643.             {
  644.                 txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width - 130, 150 );
  645.                 txtHelper.DrawTextLine( L"       Tiny control:\n"
  646.                                         L"Move forward\n"
  647.                                         L"Turn\n"
  648.                                         L"Run mode\n" );
  649.                 txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width - 35, 150 );
  650.                 txtHelper.DrawTextLine( L"\n"
  651.                                         L"W\n"
  652.                                         L"A,D\n"
  653.                                         L"Shift\n" );
  654.             }
  655.  
  656.             int i;
  657.             CTiny * pChar = g_v_pCharacters[ g_dwFollow ];
  658.             vector < String > v_sReport;
  659.             pChar->Report( v_sReport );
  660.             txtHelper.SetInsertionPos( 5, pd3dsdBackBuffer->Height - 115 );
  661.             for( i = 0; i < 6; ++i )
  662.             {
  663.                 txtHelper.DrawTextLine(v_sReport[i].c_str() );
  664.             }
  665.             txtHelper.DrawTextLine( v_sReport[16].c_str() );
  666.  
  667.             txtHelper.SetInsertionPos( 210, pd3dsdBackBuffer->Height - 85 );
  668.             for( i = 6; i < 11; ++i )
  669.             {
  670.                 txtHelper.DrawTextLine( v_sReport[i].c_str() );
  671.             }
  672.  
  673.             txtHelper.SetInsertionPos( 370, pd3dsdBackBuffer->Height - 85 );
  674.             for( i = 11; i < 16; ++i )
  675.             {
  676.                 txtHelper.DrawTextLine( v_sReport[i].c_str() );
  677.             }
  678.         } else
  679.             txtHelper.DrawTextLine( L"\n"
  680.                                     L"Quit: Esc" );
  681.     } else
  682.     {
  683.         if( g_dwFollow != 0xffffffff )
  684.             txtHelper.DrawTextLine( L"Press F1 to display animation info\n"
  685.                                     L"Quit: Esc" );
  686.         else
  687.             txtHelper.DrawTextLine( L"\n"
  688.                                     L"Quit: Esc" );
  689.     }
  690.  
  691.     txtHelper.End();
  692. }
  693.  
  694.  
  695. //--------------------------------------------------------------------------------------
  696. // Before handling window messages, the sample framework passes incoming windows 
  697. // messages to the application through this callback function. If the application sets 
  698. // *pbNoFurtherProcessing to TRUE, then the sample framework will not process this message.
  699. //--------------------------------------------------------------------------------------
  700. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
  701. {
  702.     // Give the dialogs a chance to handle the message first
  703.     *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
  704.     if( *pbNoFurtherProcessing )
  705.         return 0;
  706.     *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
  707.     if( *pbNoFurtherProcessing )
  708.         return 0;
  709.  
  710.     // Pass messages to camera class for camera movement if the
  711.     // global camera if active
  712.     if( -1 == g_dwFollow )
  713.         g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
  714.  
  715.     return 0;
  716. }
  717.  
  718.  
  719. //--------------------------------------------------------------------------------------
  720. // As a convenience, the sample framework inspects the incoming windows messages for
  721. // keystroke messages and decodes the message parameters to pass relevant keyboard
  722. // messages to the application.  The framework does not remove the underlying keystroke 
  723. // messages, which are still passed to the application's MsgProc callback.
  724. //--------------------------------------------------------------------------------------
  725. void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown )
  726. {
  727.     if( bKeyDown )
  728.     {
  729.         switch( nChar )
  730.         {
  731.             case VK_F1: g_bShowHelp = !g_bShowHelp; break;
  732.         }
  733.     }
  734. }
  735.  
  736.  
  737. //--------------------------------------------------------------------------------------
  738. // Handles the GUI events
  739. //--------------------------------------------------------------------------------------
  740. void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl )
  741. {
  742.     switch( nControlID )
  743.     {
  744.         case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
  745.         case IDC_TOGGLEREF:        DXUTToggleREF(); break;
  746.         case IDC_CHANGEDEVICE:     DXUTSetShowSettingsDialog( !DXUTGetShowSettingsDialog() ); break;
  747.         case IDC_ADDTINY:
  748.         {
  749.             CTiny * pTiny = new CTiny;
  750.             if( pTiny == NULL )
  751.                 break;
  752.  
  753.             if( SUCCEEDED( pTiny->Setup( & g_MultiAnim, & g_v_pCharacters, & g_DSound, DXUTGetGlobalTimer()->GetTime() ) ) )
  754.                 pTiny->SetSounds( g_bPlaySounds );
  755.             else
  756.                 delete pTiny;
  757.             break;
  758.         }
  759.  
  760.         case IDC_NEXTVIEW:
  761.             if( g_v_pCharacters.size() != 0 )
  762.             {
  763.                 if( g_dwFollow == 0xffffffff )
  764.                     g_dwFollow = 0;
  765.                 else if( g_dwFollow == (DWORD) g_v_pCharacters.size() - 1 )
  766.                     g_dwFollow = 0xffffffff;
  767.                 else
  768.                     ++g_dwFollow;
  769.  
  770.                 if( g_dwFollow == 0xffffffff )
  771.                 {
  772.                     g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetEnabled( false );
  773.                     g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetVisible( false );
  774.                 } else
  775.                 {
  776.                     g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetEnabled( true );
  777.                     g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetVisible( true );
  778.                     g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetChecked( g_v_pCharacters[g_dwFollow]->IsUserControl() );
  779.                 }
  780.             }
  781.             break;
  782.  
  783.         case IDC_PREVVIEW:
  784.             if( g_v_pCharacters.size() != 0 )
  785.             {
  786.                 if( g_dwFollow == 0xffffffff )
  787.                     g_dwFollow = (DWORD) g_v_pCharacters.size() - 1;
  788.                 else if( g_dwFollow == 0 )
  789.                     g_dwFollow = 0xffffffff;
  790.                 else
  791.                     --g_dwFollow;
  792.  
  793.                 if( g_dwFollow == 0xffffffff )
  794.                 {
  795.                     g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetEnabled( false );
  796.                     g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetVisible( false );
  797.                 } else
  798.                 {
  799.                     g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetEnabled( true );
  800.                     g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetVisible( true );
  801.                     g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetChecked( g_v_pCharacters[g_dwFollow]->IsUserControl() );
  802.                 }
  803.             }
  804.             break;
  805.  
  806.         case IDC_RESETCAMERA:
  807.             g_dwFollow = 0xffffffff;
  808.             g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetEnabled( false );
  809.             g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetVisible( false );
  810.             break;
  811.  
  812.         case IDC_ENABLESOUND:
  813.         {
  814.             g_bPlaySounds = ((CDXUTCheckBox*)pControl)->GetChecked();
  815.             vector< CTiny* >::iterator itCur, itEnd = g_v_pCharacters.end();
  816.             for( itCur = g_v_pCharacters.begin(); itCur != itEnd; ++ itCur )
  817.                 ( * itCur )->SetSounds( g_bPlaySounds );
  818.             break;
  819.         }
  820.  
  821.         case IDC_CONTROLTINY:
  822.             if( g_dwFollow != 0xffffffff )
  823.             {
  824.                 CTiny * pChar = g_v_pCharacters[ g_dwFollow ];
  825.                 if( ((CDXUTCheckBox*)pControl)->GetChecked() )
  826.                     pChar->SetUserControl();
  827.                 else
  828.                     pChar->SetAutoControl();
  829.             }
  830.             break;
  831.  
  832.         case IDC_RELEASEALL:
  833.         {
  834.             vector< CTiny* >::iterator itCur, itEnd = g_v_pCharacters.end();
  835.             for( itCur = g_v_pCharacters.begin(); itCur != itEnd; ++ itCur )
  836.                 ( * itCur )->SetAutoControl();
  837.             g_SampleUI.GetCheckBox( IDC_CONTROLTINY )->SetChecked( false );
  838.             break;
  839.         }
  840.  
  841.         case IDC_RESETTIME:
  842.         {
  843.             DXUTGetGlobalTimer()->Reset();
  844.             g_fLastAnimTime = DXUTGetGlobalTimer()->GetTime();
  845.             vector< CTiny* >::iterator itCur, itEnd = g_v_pCharacters.end();
  846.             for( itCur = g_v_pCharacters.begin(); itCur != itEnd; ++ itCur )
  847.                 ( * itCur )->ResetTime();
  848.             break;
  849.         }
  850.     }
  851. }
  852.  
  853.  
  854. //--------------------------------------------------------------------------------------
  855. // This callback function will be called immediately after the Direct3D device has 
  856. // entered a lost state and before IDirect3DDevice9::Reset is called. Resources created
  857. // in the OnResetDevice callback should be released here, which generally includes all 
  858. // D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for 
  859. // information about lost devices.
  860. //--------------------------------------------------------------------------------------
  861. void CALLBACK OnLostDevice()
  862. {
  863.     if( g_pFont )
  864.         g_pFont->OnLostDevice();
  865.     if( g_pEffect )
  866.         g_pEffect->OnLostDevice();
  867.     ID3DXEffect *pMAEffect = g_MultiAnim.GetEffect();
  868.     if( pMAEffect )
  869.     {
  870.         pMAEffect->OnLostDevice();
  871.         pMAEffect->Release();
  872.     }
  873.  
  874.     SAFE_RELEASE( g_pTextSprite );
  875.     SAFE_RELEASE( g_pMeshFloor );
  876.  
  877.     vector< CTiny* >::iterator itCurCP, itEndCP = g_v_pCharacters.end();
  878.     for( itCurCP = g_v_pCharacters.begin(); itCurCP != itEndCP; ++ itCurCP )
  879.     {
  880.         ( *itCurCP )->InvalidateDeviceObjects();
  881.     }
  882.  
  883.     CMultiAnimAllocateHierarchy AH;
  884.     AH.SetMA( & g_MultiAnim );
  885.     g_MultiAnim.Cleanup( & AH );
  886. }
  887.  
  888.  
  889. //--------------------------------------------------------------------------------------
  890. // This callback function will be called immediately after the Direct3D device has 
  891. // been destroyed, which generally happens as a result of application termination or 
  892. // windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  893. // should be released here, which generally includes all D3DPOOL_MANAGED resources. 
  894. //--------------------------------------------------------------------------------------
  895. void CALLBACK OnDestroyDevice()
  896. {
  897.     SAFE_RELEASE(g_pEffect);
  898.     SAFE_RELEASE(g_pFont);
  899.  
  900.     SAFE_RELEASE( g_pTxFloor );
  901.     SAFE_RELEASE( g_pMeshFloor );
  902. }
  903.